package com.wei.c.widget;

import android.animation.Animator;
import android.animation.Animator.AnimatorListener;
import android.animation.AnimatorInflater;
import android.annotation.SuppressLint;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AnimationUtils;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.ImageView.ScaleType;

import com.wei.c.lib.R;
import com.wei.c.widget.SlideEventTracker.Result;

public class LockView extends FrameLayout {
    private static final boolean DEBUG = false;
    private static final String TAG = DEBUG ? "LockView" : LockView.class.getSimpleName();

    private SlideEventTracker mSlideTracker;
    private ViewGroup mContainer;
    private OnLockSlideListener mOnLockSlideListener;
    private boolean mResetRequest;

    private int mCurrScrollX;
    private ImageView mImageView;
    private int mUnlockIconCenterToBorder = -1;
    private int mAdsorbCenter;

    public LockView(Context context) {
        super(context);
        init();
    }

    public LockView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public LockView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        mImageView = new ImageView(getContext());
        mImageView.setScaleType(ScaleType.CENTER);
        final LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
        lp.gravity = Gravity.CENTER;
        mImageView.setImageResource(R.drawable.lock);
        //mImageView.setBackgroundResource(R.drawable.lock_btn_ring_s);
        addViewInLayout(mImageView, -1, lp);
        setBackgroundResource(R.drawable.lock_btn_ring_s);

        mSlideTracker = new SlideEventTracker(this, 45, 1, 1, 80, 80, null,
                AnimationUtils.loadInterpolator(getContext(), android.R.anim.decelerate_interpolator),
                mOnSlideListener, mOnScrollListener, false);
        /*mSlideTracker = new SlideEventTracker(this, 45, 1, 80,
                AnimationUtils.loadInterpolator(getContext(), android.R.anim.decelerate_interpolator),
                mOnSlideListener, mOnScrollListener, true);*/
    }

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        mContainer = (ViewGroup)getParent();
        if (mResetRequest) reset();
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        if (mUnlockIconCenterToBorder == -1) {
            setUnlockIconCenterToBorder(getWidth());
        } else {
            updateAdsorbCenter();
        }
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        Result result = mSlideTracker.preDispatchTouchEvent(ev);
        return result.performSuper ? mSlideTracker.postDispatchTouchEvent(ev, super.dispatchTouchEvent(result.superEvent)) : result.consume();
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        Result result = mSlideTracker.preOnInterceptTouchEvent(ev);
        return result.performSuper ? mSlideTracker.postOnInterceptTouchEvent(ev, super.onInterceptTouchEvent(result.superEvent)) : result.consume();
    }

    @Override
    @SuppressLint("ClickableViewAccessibility")
    public boolean onTouchEvent(MotionEvent ev) {
        Result result = mSlideTracker.preOnTouchEvent(ev);
        return result.performSuper ? mSlideTracker.postOnTouchEvent(ev, super.onTouchEvent(result.superEvent)) : result.consume();
    }

    private final SlideEventTracker.OnSlideListener mOnSlideListener = new SlideEventTracker.OnSlideListener() {
        private int downScrollX, toCenterX;
        private float adsorbCoefficient;

        @Override
        public void onSlideEventBeginX(MotionEvent ev, boolean prevAnimInterrupted) {
            downScrollX = mContainer.getScrollX();
            toCenterX = (int)(ev.getX() - getWidth() / 2.0f);
            adsorbCoefficient = 1;
            onTouch();
        }

        @Override
        public void onSlideEventBeginY(MotionEvent ev, boolean prevAnimInterrupted) {}

        @Override
        public void onSlideEventMoveX(boolean haveSlideIntention, int scrollBy) {
            //if (haveSlideIntention) {
            mSlideTracker.smoothScrollX(mCurrScrollX, (int)((downScrollX - scrollBy - toCenterX) * adsorbCoefficient));
            //}
        }

        @Override
        public void onSlideEventMoveY(boolean haveSlideIntention, int scrollBy) {
            scrollBy = Math.abs(scrollBy);
            final int height = getHeight();
            adsorbCoefficient = scrollBy <= height ? 1 : height * 1f / scrollBy;
            if (DEBUG) Log.d(TAG, "onSlideEventMoveY----scrollBy:" + scrollBy + ", adsorbCoefficient:" + adsorbCoefficient);
        }

        @Override
        public void onSlideEventEndX(boolean haveSlideIntention, boolean prevAnimInterrupted, float velocity, boolean sysDefFling) {
            if (!haveSlideIntention) {
                startTouchEndAnim();
                mCurrScrollX = 0;
                mContainer.setScrollX(0);
                mSlideTracker.abortScrollX();
            } else {
                if (DEBUG) Log.d(TAG, "onSlideEventEndX----mCurrScrollX - downScrollX:" + (mCurrScrollX - downScrollX) + ", velocity:" + velocity + ", sysDefFling:" + sysDefFling);
                int target;
                if (sysDefFling && Math.abs(mCurrScrollX - downScrollX) >= mAdsorbCenter / 3) {
                    if (velocity > 0) { //向右
                        if (mCurrScrollX > 0) { //左边则归零
                            target = 0;
                        } else {    //最右边
                            target = -mAdsorbCenter;
                        }
                    } else {
                        if (mCurrScrollX > 0) { //左边则到最左
                            target = mAdsorbCenter;
                        } else {    //归零
                            target = 0;
                        }
                    }
                } else {
                    if (Math.abs(mCurrScrollX) >= mAdsorbCenter - getWidth()) {
                        if (mCurrScrollX > 0) { //左边则到最左
                            target = mAdsorbCenter;
                        } else {    //归零
                            target = -mAdsorbCenter;
                        }
                    } else {
                        target = 0;
                    }
                }
                if (DEBUG) Log.d(TAG, "onSlideEventEndX----mCurrScrollX:" + mCurrScrollX + ", target:" + target + ", mAdsorbCenter:" + mAdsorbCenter);
                if (target == mCurrScrollX) {
                    mSlideTracker.abortScrollX();
                    mOnScrollListener.onScrollFinishedX();
                } else {
                    mSlideTracker.startScrollX(mCurrScrollX, target, 150);
                }
            }
        }

        @Override
        public void onSlideEventEndY(boolean haveSlideIntention, boolean prevAnimInterrupted, float velocity, boolean sysDefFling) {}
    };

    private final SlideEventTracker.OnScrollListener mOnScrollListener = new SlideEventTracker.OnScrollListener() {

        @Override
        public void onScrollToX(int target, float velocity, boolean touching) {
            if (Math.abs(target) > mAdsorbCenter - getWidth()) {
                if (Math.abs(mCurrScrollX) != mAdsorbCenter) {
                    onAdsorbEnter(target > 0);
                }
                if (target < 0) {   //向右
                    target = -mAdsorbCenter;
                } else {
                    target = mAdsorbCenter;
                }
            } else if (Math.abs(mCurrScrollX) == mAdsorbCenter) {
                onAdsorbExit(mCurrScrollX > 0);
            }
            mCurrScrollX = target;
            mContainer.setScrollX(target);
            onScrollTo(target);
        }

        @Override
        public void onScrollToY(int target, float velocity, boolean touching) {}

        @Override
        public void onScrollFinishedX() {
            if (DEBUG) Log.e(TAG, "onScrollFinishedX----mCurrScrollX:" + mCurrScrollX);
            startTouchEndAnim();
            onScrollFinish(mCurrScrollX == 0 ? 0 : mCurrScrollX > 0 ? -1 : 1);
        }

        @Override
        public void onScrollFinishedY() {}
    };

    @Override
    public void computeScroll() {
        super.computeScroll();
        mSlideTracker.onComputeScroll();
    };

    private Animator mTouchStartAnimator;
    private void startTouchStartAnim() {
        if (mTouchStartAnimator == null) {
            mTouchStartAnimator = AnimatorInflater.loadAnimator(getContext(), R.animator.lock_btn_touch_start);
            mTouchStartAnimator.setTarget(this);
        }
        if (mTouchEndAnimator != null) mTouchEndAnimator.cancel();
        mTouchStartAnimator.cancel();
        mImageView.setVisibility(View.INVISIBLE);
        mTouchStartAnimator.start();
    }

    private Animator mTouchEndAnimator;
    private void startTouchEndAnim() {
        if (mTouchEndAnimator == null) {
            mTouchEndAnimator = AnimatorInflater.loadAnimator(getContext(), R.animator.lock_btn_touch_end);
            mTouchEndAnimator.setTarget(this);
            mTouchEndAnimator.addListener(new AnimatorListener() {

                @Override
                public void onAnimationStart(Animator animation) {}

                @Override
                public void onAnimationRepeat(Animator animation) {}

                @Override
                public void onAnimationEnd(Animator animation) {
                    mImageView.setVisibility(View.VISIBLE);
                    LockView.this.setScaleX(1);
                    LockView.this.setScaleY(1);
                    onResetAnimEnd();
                }

                @Override
                public void onAnimationCancel(Animator animation) {}
            });
        }
        if (mTouchStartAnimator != null) mTouchStartAnimator.cancel();
        mTouchEndAnimator.cancel();
        mTouchEndAnimator.start();
    }

    public void setUnlockIconCenterToBorder(int border) {
        mUnlockIconCenterToBorder = border;
        if (getWidth() > 0) updateAdsorbCenter();
    }

    private void updateAdsorbCenter() {
        mAdsorbCenter = mContainer.getWidth() / 2 - mUnlockIconCenterToBorder;
    }

    public void reset() {
        if (mContainer != null) {
            mContainer.setScrollX(0);
            mResetRequest = false;
        } else {
            mResetRequest = true;
        }
    }

    public void setOnLockSlideListener(OnLockSlideListener l) {
        mOnLockSlideListener = l;
    }

    protected void onTouch() {
        startTouchStartAnim();
        if (mOnLockSlideListener != null) mOnLockSlideListener.onTouch();
    }

    protected void onAdsorbEnter(boolean trueLeftFalseRight) {
        startTouchStartAnim();
        if (mOnLockSlideListener != null) mOnLockSlideListener.onAdsorbEnter(trueLeftFalseRight);
    }

    protected void onAdsorbExit(boolean trueLeftFalseRight) {
        //startTouchStartAnim();
        if (mOnLockSlideListener != null) mOnLockSlideListener.onAdsorbExit(trueLeftFalseRight);
    }

    protected void onScrollTo(int scrollTo) {
        if (mOnLockSlideListener != null) mOnLockSlideListener.onScrollTo(scrollTo);
    }

    protected void onScrollFinish(int direction) {
        if (mOnLockSlideListener != null) mOnLockSlideListener.onScrollFinish(direction);
    }

    protected void onResetAnimEnd() {
        if (mOnLockSlideListener != null) mOnLockSlideListener.onResetAnimEnd();
    }

    public static interface OnLockSlideListener {
        /**
         * 手指按下。
         */
        void onTouch();
        /**
         * 进入吸附区。
         * @param trueLeftFalseRight true表示左边，false表示右边。
         */
        void onAdsorbEnter(boolean trueLeftFalseRight);
        /**
         * 离开吸附区。
         * @param trueLeftFalseRight true表示左边，false表示右边。
         */
        void onAdsorbExit(boolean trueLeftFalseRight);
        /**
         * 正在滚动的距离。（并不完全与手指一致，如果手速较快，会有个动画过度，这里是动画的当前位置，也就是看到的实际位置）
         * @param scrollTo >0左，0中，<0右
         */
        void onScrollTo(int scrollTo);
        /**
         * 拖动松开后的滚动（滑到左右或中间复位）动画结束。
         * @param direction -1左，0中，1右
         */
        void onScrollFinish(int direction);
        /**
         * 中间复位动画结束。
         */
        void onResetAnimEnd();
    }
}
